package ve.com.wayoyo.wuml_case.DibujoDiagramas;

import ve.com.wayoyo.wuml_case.Alert;
import ve.com.wayoyo.wuml_case.Exceptions.PertCpmWebException;
import ve.com.wayoyo.wuml_case.Exceptions.TituloVacioExecption;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Point;

public class DiagramaGrafos extends Diagrama {

	public DiagramaGrafos() {
		super();
		Nombre = "";
		Tipo = "grafo";
	}

	@Override
	public void moverItemSeleccionado(int distX, int distY) {
		if (_tutorialStage == 2) {
			_tutorialStage = 3;
		}
		if (SelectedItem != null) {
			SelectedItem.mover(distX, distY);
			SelectedItem.actualizarPuntoCentral();
		}
	}

	@Override
	public void Dibujar(Canvas c, int offSetX, int offSetY, float GlobalScale) {
		// Scroll Bars
		if (((VistaDiagrama) VistaDiagrama.getVista()).getMoveFlag() == true) {
			dibujarScrollBars(c, offSetX, offSetY, GlobalScale);
		}

		// Zoom Helper
		if (((VistaDiagrama) VistaDiagrama.getVista()).isZooming() == true) {
			dibujarZoomGuide(c, GlobalScale);
		}

		// Muestra la ventana de ayuda
		if (_showHelp) {
			dibujarAyuda(c);
		}

		// Muestra los tips en el fondo de la pantalla
		if (_showTutorial) {
			dibujarTutorial(c);
		}

		for (Componente Value : _components) {
			// if(Value.CalcularVisibilidad(offSetX,offSetY,GlobalScale)){
			Value.Dibujar(c, false, GlobalScale, offSetX, offSetY);
			// }
		}
		
	}

	@Override
	public int checkOnTouch(Point touchPoint, String type) {
		CompConector aux = null;
		int respuesta = VistaDiagrama.IDLE;
		if (type.equals("Select")) {
			for (Componente Value : _components) {
				if (Value.calcularTouch(touchPoint) == true) {
					respuesta = VistaDiagrama.ITEM_SELECTED;
					resetFocus();
					if (_SelectedConector != null) {
						_SelectedConector.setState(CompConector.IDLE_STATE);
						getComponenteById(_SelectedConector.get_fatherId()).set_currentState(Componente.IDLE);
						getComponenteById(_SelectedConector.get_childId()).set_currentState(Componente.IDLE);
						_SelectedConector = null;
					}
					SelectedItem = Value;
					SelectedItem.set_currentState(Componente.SELECTED);
					_SelectedConector = null;
					break;
				} else {
					if (aux == null) {
						aux = Value.calcularTouchConectores(touchPoint);
					}
				}
			}
			if (aux != null) {
				_SelectedConector = aux;
				respuesta = VistaDiagrama.CONNECTOR_SELECTED;
				resetFocus();
				_SelectedConector.setState(CompConector.SELECTED_STATE);
				getComponenteById(_SelectedConector.get_fatherId())
						.set_currentState(Componente.LINKED);
				getComponenteById(_SelectedConector.get_childId())
						.set_currentState(Componente.LINKED);
			}
		}else if (type.equals("Connect")) {
			for (Componente Value : _components) {
				if (Value.calcularTouch(touchPoint) == true && (Value.isConnectable())) {
					if((Value.ID != SelectedItem.ID) || Value.isAllowRecursivity()){
						respuesta = VistaDiagrama.ITEM_SELECTED;
						CompLineConector nuevo;
						nuevo = new CompLineConector(SelectedItem.ID, Value.ID);
						nuevo.setCosto(1);
						Value.actualizarAchorsPoints();
						Value.actualizarPuntoCentral();
						SelectedItem.actualizarAchorsPoints();
						SelectedItem.actualizarPuntoCentral();
						nuevo.CalcularConexiones(SelectedItem, Value);
						SelectedItem._conectorsBegining.add(nuevo);
						Value._conectorsEnd.add(nuevo);
						SelectedItem.set_currentState(Componente.SELECTED);
						if (_tutorialStage == 3) {
							_showTutorial = false;
							_tutorialStage = 4;
						}
						break;
					}else{
						Alert.show("Este Componente no admite recursividad", (Activity) VistaDiagrama.getVista().getContext(), Alert.ERROR);
					}
				}
			}
		}else if(type.equals("CalcularDistancia")){
			respuesta = VistaDiagrama.CALCULATING_DIJKSTRA;
			for (Componente Value : _components) {
				if (Value.calcularTouch(touchPoint) == true) {
					if(Value.getState() == Componente.AVIABLE_NODE){						
						Value.set_currentState(Componente.FINAL_NODE);
						dijkstraRun((CompNodo)getSelectedItem());
						for (Componente Extra : _components) {
							if(Extra.get_currentState() != Componente.FINAL_NODE && Extra.get_currentState() != Componente.INITIAL_NODE
								&& Extra.get_currentState() != Componente.UNAVIABLE_NODE && !((CompNodo)Extra).isVisited()){
								dijkstraRun((CompNodo)Extra);
							}
						}
						showDist((CompNodo)Value);
						for (Componente Other : _components) {
							if(Other.get_currentState() != Componente.FINAL_NODE && Other.get_currentState() != Componente.INITIAL_NODE
									&& Other.get_currentState() != Componente.PATH_NODE){
								Other.set_currentState(Componente.IDLE);
							}

						}
						respuesta = VistaDiagrama.SHOWING_RESUTLS;
						
					}else{
						Alert.show("Este nodo no es accesible",(Activity) VistaDiagrama.getVista().getContext(), Alert.WARNING);
					}
					
				}
			}
		}else if(type.equals("CalcularPertCpm")){
			respuesta = VistaDiagrama.CALCULATING_PERTCPM;
			for (Componente Value : _components) {
				if (Value.calcularTouch(touchPoint) == true) {
					if(Value.get_currentState() == Componente.AVIABLE_NODE){
						try{
							Value.set_currentState(Componente.FINAL_NODE);
							calcularPERTCPM(Value);							
							respuesta = VistaDiagrama.SHOWING_RESUTLS;
						}catch (PertCpmWebException e) {
							Alert.show(e.getMessage(),(Activity) VistaDiagrama.getVista().getContext(), Alert.ERROR);
							cleaRresults();
							respuesta = VistaDiagrama.ITEM_SELECTED;
						}
					}
				}
			}

		}
		
		return respuesta;
	}
	
	public void calcularPERTCPM(Componente Value) throws PertCpmWebException{
		try {
			fowardPertCpm(0, (CompNodo)SelectedItem);
			backwardPertCpm(((CompNodo)Value).getTriangleCase(), (CompNodo)Value);
			identifyCP((CompNodo)SelectedItem);
		} catch (PertCpmWebException e) {
			throw e;
		}
		
	}

	@Override
	public void resetFocus() {
		for (Componente Value : _components) {
			Value.removeFocus();
			try{
				((CompNodo)Value).setDistCost(Float.MAX_VALUE);
				((CompNodo)Value).setShowPert(false);
			}catch (Exception e) {
				System.out.println(e.getMessage());
			}
		}
		SelectedItem = null;
	}
	
	public void cleaRresults(){
			for (Componente Value : _components) {
				Value.removeFocus();
				try{
					((CompNodo)Value).setDistCost(Float.MAX_VALUE);
					((CompNodo)Value).setShowPert(false);
				}catch (Exception e) {
					System.out.println(e.getMessage());
				}
			}
			SelectedItem.set_currentState(Componente.SELECTED);
	}

	@Override
	public boolean validarNombre(String nuevo) throws TituloVacioExecption {
		boolean respuesta = true;
		if (nuevo.length() < 1) {
			throw new TituloVacioExecption();
		}
		return respuesta;
	}

	public void prepararCalculoDistMasCorta() {
		for (Componente value : _components) {
			if(value instanceof CompNodo){
				((CompNodo)value).setDistCost(Float.MAX_VALUE);
				((CompNodo)value).setPrevNodePath(null);
				((CompNodo)value).setVisited(false);
			}
		}
		try{
			((CompNodo)SelectedItem).setDistCost(0);
			checkAviavility(SelectedItem);
		}catch (Exception e) {
			System.out.println(e.getMessage());
		}
		SelectedItem.set_currentState(Componente.INITIAL_NODE);
		for (Componente value : _components) {
			if (value.getState() != Componente.INITIAL_NODE && value.getState() != Componente.AVIABLE_NODE) {
				value.set_currentState(Componente.UNAVIABLE_NODE);
			}
		}
	}
	
	public void perpararPertCpm(){
		for (Componente value : _components) {
			if(value instanceof CompNodo){
				((CompNodo)value).setSquareCase(Float.MIN_VALUE);
				((CompNodo)value).setTriangleCase(Float.MAX_VALUE);
				((CompNodo)value).setVisited(false);
			}
		}
		try{
			((CompNodo)SelectedItem).setDistCost(0);
			checkAviavilityPertCpm(SelectedItem);
			((CompNodo)SelectedItem).setSquareCase(0);
		}catch (Exception e) {
			System.out.println(e.getMessage());
		}
		SelectedItem.set_currentState(Componente.INITIAL_NODE);
		
		for (Componente value : _components) {
			if (value.getState() != Componente.INITIAL_NODE && value.getState() != Componente.AVIABLE_NODE) {
				value.set_currentState(Componente.UNAVIABLE_NODE);
			}
		}
	}
	
	public void checkAviavilityPertCpm(Componente nodo){
		if(nodo.getState() != Componente.AVIABLE_NODE){
			nodo.set_currentState(Componente.AVIABLE_NODE);
			for (CompConector value : nodo._conectorsBegining) {
				if((value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
				   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
					
					checkAviavilityPertCpm((CompNodo)getComponenteById(value._childId));
				}
			}
			for (CompConector value : nodo._conectorsEnd) {
				if((value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
				   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
					
					checkAviavilityPertCpm((CompNodo)getComponenteById(value._fatherId));
				}
			}
		}
	}
	
	public void checkAviavility(Componente nodo){
		if(nodo.getState() != Componente.AVIABLE_NODE){
			nodo.set_currentState(Componente.AVIABLE_NODE);
			for (CompConector value : nodo._conectorsBegining) {
				if((value._childArrowType == CompConector._arrowType.Asociacion &&  value._fatherArrowType == CompConector._arrowType.Asociacion)|| 
				   (value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
				   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
					
					checkAviavility((CompNodo)getComponenteById(value._childId));
				}
			}
			for (CompConector value : nodo._conectorsEnd) {
				if((value._childArrowType == CompConector._arrowType.Asociacion &&  value._fatherArrowType == CompConector._arrowType.Asociacion)|| 
						   (value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
						   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
					checkAviavility((CompNodo)getComponenteById(value._fatherId));
				}
			}
		}
	}
	
	public void dijkstraRun(CompNodo nodo){
		float dist;
		CompNodo next;
		float minDist = Float.MAX_VALUE;
		int NextID = -1;
		if(!nodo.isVisited() && nodo.get_currentState() != Componente.FINAL_NODE){
			for (CompConector value : nodo._conectorsBegining) {
				if((value._childArrowType == CompConector._arrowType.Asociacion &&  value._fatherArrowType == CompConector._arrowType.Asociacion)|| 
						   (value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
						   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
					next = (CompNodo)getComponenteById(value._childId);
					dist = nodo.getDistCost()+value.getCosto();
					String prevName = nodo.getTitulo();
					String postName = next.getTitulo();
					
					if(dist < next.getDistCost()){
						next.setDistCost(dist);
						next.setPrevNodePath(value);
						next.setVisited(false);
					}
					if(!next.isVisited()){
						if(dist < minDist){
							minDist = dist;
							NextID = next.getID();
						}
					}
				}
			}
			for (CompConector value : nodo._conectorsEnd) {
				if((value._childArrowType == CompConector._arrowType.Asociacion &&  value._fatherArrowType == CompConector._arrowType.Asociacion)|| 
						   (value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
						   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
					next = (CompNodo)getComponenteById(value._fatherId);
					if(!next.isVisited()){
						String prevName = nodo.getTitulo();
						String postName = next.getTitulo();
						dist = nodo.getDistCost()+value.getCosto();
						
						if(dist < next.getDistCost()){
							next.setDistCost(dist);
							next.setPrevNodePath(value);
							next.setVisited(false);
						}
						if(!next.isVisited()){
							if(dist < minDist){
								minDist = dist;
								NextID = next.getID();
							}
						}
					}
				}
			}
			nodo.setVisited(true);
			if(NextID != -1){
				dijkstraRun((CompNodo)getComponenteById(NextID));
			}
		}
	}
	
	
	public boolean fowardPertCpm(float prevCost, CompNodo nodo) throws PertCpmWebException{
		boolean respuesta = false;
		if(nodo.isVisited() == false){
			if(nodo.get_currentState() == Componente.FINAL_NODE){
				if(prevCost >= nodo.getSquareCase()){
					nodo.setSquareCase(prevCost);
					nodo.setTriangleCase(prevCost);
				}
				respuesta = true;
			}else{
				nodo.setVisited(true);
				if(prevCost >= nodo.getSquareCase()){
						nodo.setSquareCase(prevCost);
						for (CompConector value : nodo._conectorsBegining) {
							if((value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
							   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
								
								fowardPertCpm(prevCost+value.getCosto(),(CompNodo)getComponenteById(value._childId));
							}
						}
						for (CompConector value : nodo._conectorsEnd) {
							if((value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
							   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
								
								fowardPertCpm(prevCost+value.getCosto(),(CompNodo)getComponenteById(value._fatherId));
							}
						}
						
				}
				nodo.setVisited(false);
			}
		}else{
			throw new PertCpmWebException();
		}
		return respuesta;
	}
	
	public boolean backwardPertCpm(float prevCost, CompNodo nodo){
		boolean respuesta = false;
		if(nodo.isVisited() == false){
			if(nodo.get_currentState() == Componente.INITIAL_NODE){
				if(prevCost <= nodo.getTriangleCase()){
					nodo.setTriangleCase(prevCost);
				}
				respuesta = true;
			}else{
				nodo.setVisited(true);
				if(prevCost <= nodo.getTriangleCase()){
						nodo.setTriangleCase(prevCost);
						for (CompConector value : nodo._conectorsBegining) {
							if((value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
							   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
								
								backwardPertCpm(prevCost-value.getCosto(),(CompNodo)getComponenteById(value._childId));
							}
						}
						for (CompConector value : nodo._conectorsEnd) {
							if((value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
							   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
								
								backwardPertCpm(prevCost-value.getCosto(),(CompNodo)getComponenteById(value._fatherId));
							}
						}	
				}
				nodo.setVisited(false);
			}
		}
		return respuesta;
	}
	
	public void identifyCP(CompNodo nodo){
		if(nodo.getSquareCase() != Float.MIN_VALUE && nodo.getTriangleCase() != Float.MAX_VALUE){
			nodo.setShowPert(true);
		}
		if(nodo.getTriangleCase() == nodo.getSquareCase()){
			nodo.set_currentState(Componente.PATH_NODE);
		}else if(nodo.get_currentState() == Componente.AVIABLE_NODE){
			nodo.set_currentState(Componente.IDLE);
		}
		for (CompConector value : nodo._conectorsBegining) {
			if((value._childArrowType == CompConector._arrowType.Asociacion_Directa && value._fatherArrowType == CompConector._arrowType.Asociacion) || 
			   (value._childArrowType == CompConector._arrowType.Herencia && value._fatherArrowType == CompConector._arrowType.Asociacion)){
				float otherTC = ((CompNodo)getComponenteById(value._childId)).getTriangleCase();
				float otherSC = ((CompNodo)getComponenteById(value._childId)).getSquareCase();
				if(nodo.getTriangleCase() == otherTC - value.getCosto() &&
				   nodo.getSquareCase() == otherSC - value.getCosto() &&
				   nodo.getTriangleCase() == nodo.getSquareCase()){
					value.setState(CompConector.PATH_STATE);
				}
				identifyCP((CompNodo)getComponenteById(value._childId));
			}
		}
		for (CompConector value : nodo._conectorsEnd) {
			if((value._fatherArrowType == CompConector._arrowType.Asociacion_Directa && value._childArrowType == CompConector._arrowType.Asociacion) || 
			   (value._fatherArrowType == CompConector._arrowType.Herencia && value._childArrowType == CompConector._arrowType.Asociacion)){
				float otherTC = ((CompNodo)getComponenteById(value._fatherId)).getTriangleCase();
				float otherSC = ((CompNodo)getComponenteById(value._fatherId)).getSquareCase();
				if(nodo.getTriangleCase() == otherTC - value.getCosto() &&
				   nodo.getSquareCase() == otherSC - value.getCosto()){
					value.setState(CompConector.PATH_STATE);
				}
				identifyCP((CompNodo)getComponenteById(value._fatherId));
				
			}
		}
	}
	public void showDist(CompNodo actual){
		if(actual.getState() != Componente.INITIAL_NODE){
			actual.set_currentState(Componente.PATH_NODE);
			actual.getPrevNodePath().setState(CompConector.PATH_STATE);
			if(actual.getPrevNodePath().get_fatherId() == actual.getID()){
				showDist((CompNodo)(this.getComponenteById(actual.getPrevNodePath().get_childId())));
			}else{
				showDist((CompNodo)(this.getComponenteById(actual.getPrevNodePath().get_fatherId())));
			}
		}
	}

}
